
#if	!defined( __20080906_DEF_LINUX_SIMPLEFILE_H__ )
#define	__20080906_DEF_LINUX_SIMPLEFILE_H__

#if	defined( PCE_CFG_OS_Linux )

#include	<assert.h>
#include	<stdio.h>

namespace PCE_Lib {
namespace CEnv_Def {
namespace PCE_Lib_CurrentCEnvironment {
namespace Tools {

class SimpleFile
{
public:
	enum OpenMode_t {
		OM_R	= 1,
		OM_W	= 2,
		OM_B	= 4,
		OM_T	= 8,
	};
	enum SeekBase_t {
		Seek_Set	= SEEK_SET,
		Seek_Cur	= SEEK_CUR,
		Seek_End	= SEEK_END,
	};
protected:
	static FILE * openPhysicalFile( const char_t * fname, usize_t open_mode ) throw()
	{
		assert( NotNull( fname ) );

		char	mode_str[ 5 ];
		char	* p = mode_str;

		if( OM_R & open_mode ) {
			*( p++ ) = 'r';
		}
		if( OM_W & open_mode ) {
			*( p++ ) = 'w';
		}
		if( OM_B & open_mode ) {
			*( p++ ) = 'b';
		}
		if( OM_T & open_mode ) {
			*( p++ ) = 't';
		}
		*p = 0;
		return fopen( fname, mode_str );
	}
public:
	bool Open( const char_t * fname, usize_t open_mode ) throw()
	{
		assert( NotNull( fname ) );

		if( NotNull( m_File ) ) {
			if( 0 != fclose( m_File ) ) {
				return false;
			}
		}
		m_File = openPhysicalFile( fname, open_mode );
		return NotNull( m_File );
	}
	bool Close( void ) throw()
	{
		if( NotNull( m_File ) ) {
			FILE	* tmp_file = m_File;
			SetNull( m_File );
			return 0 == fclose( tmp_file );
		}else {
			return true;
		}
	}
	bool Is_Open( void ) const throw() { return NotNull( m_File ); }
public:
	bool Read( void * buffer, usize_t size ) throw()
	{
		assert( NotNull( buffer ) );
		assert( size > 0 );
		assert( NotNull( m_File ) );

		return 1 == fread( buffer, size, 1, m_File );
	}
	bool Write( const void * buffer, usize_t size ) throw()
	{
		assert( NotNull( buffer ) );
		assert( size > 0 );
		assert( NotNull( m_File ) );

		return 1 == fwrite( buffer, size, 1, m_File );
	}
	bool Seek( int64_t offset = 0, SeekBase_t flag = Seek_Set ) throw()
	{
		assert( (Seek_Set == flag) || (Seek_Cur == flag) || (Seek_End == flag) );
		assert( NotNull( m_File ) );

		return 0 == fseek( m_File, static_cast< long >( offset ), static_cast< int >( flag ) );
	}
	bool Tell( int64_t & offset ) throw()
	{
		assert( NotNull( m_File ) );

		long tmp_offset = ftell( m_File );
		offset = static_cast< int64_t >( tmp_offset );
		return tmp_offset >= 0;
	}
	bool Length( int64_t & len ) throw()
	{
		assert( NotNull( m_File ) );

		int64_t		cur_offset;

		if( ! Tell( cur_offset ) ) {
			return false;
		}
		if( ! Seek( 0, Seek_End ) ) {
			return false;
		}
		if( ! Tell( len ) ) {
			return false;
		}
		return Seek( cur_offset, Seek_Set );
	}
	bool Reach_End( bool & is_end ) throw()
	{
		assert( NotNull( m_File ) );

		int64_t		cur_offset, len;

		if( ! Tell( cur_offset ) ) {
			return false;
		}
		if( ! Seek( 0, Seek_End ) ) {
			return false;
		}
		if( ! Tell( len ) ) {
			return false;
		}
		if( ! Seek( cur_offset, Seek_Set ) ) {
			return false;
		}
		is_end = ( cur_offset >= len );
		return true;
	}
public:
	SimpleFile( void ) throw() : m_File() {}
	SimpleFile( const char_t * fname, usize_t open_mode ) throw()
	{
		m_File = openPhysicalFile( fname, open_mode );
	}
	~SimpleFile( void ) throw()
	{
		if( NotNull( m_File) ) {
			fclose( m_File );
		}
	}
protected:
	FILE	* m_File;
};

}	// Tools
}	// PCE_Lib_CurrentCEnvironment
}	// CEnv_Def
}	// PCE_Lib

#else
	#error SimpleFile_Linux.h can only be used on Linux platform!
#endif	// PCE_CFG_OS_Linux

#endif	// __20080906_DEF_LINUX_SIMPLEFILE_H__
